#include "diskio.h"		/* FatFs lower layer API */
#include "ff.h"
#include "stdio.h"
#include "spi_flash.h"
#include "string.h"
 

#define SPI_FLASH		0	

#define SPI_FLASH_DEV	          "0:"
#define MANUFACTURE_ID_W25Q64     0xEF
#define FLASH_SECTOR_SIZE 	      4096
#define FLASH_SECTOR_COUNT        4096


BYTE gFsWork[FF_MAX_SS]; 
FATFS sysFs;
UINT bw;
FIL fil;


void file_system_init(void)
{
	FRESULT res = FR_OK;

	res = f_mount(&sysFs,SPI_FLASH_DEV,1);
	if(res == FR_OK){
		printf("file system has mount\r\n");
	}else{
		printf("file system must be mkfs\r\n");
		res = f_mkfs(SPI_FLASH_DEV, FM_FAT,0, gFsWork, sizeof(gFsWork));
		if(res == FR_OK)
		{
			res = f_mount(NULL,SPI_FLASH_DEV,1);
			res = f_mount(&sysFs,SPI_FLASH_DEV,1);
			if(res == FR_OK)
			{
				printf("file system mount ok\r\n");
			}
			else
			{
				printf("file system mount fail\r\n");
			}
		}
		else
		{
			printf("file system mkfs fail\r\n");
		}
	}
}

void Print_Files(char* path)
{
	FRESULT res;
	FILINFO fno;
	DIR dir;
	char *fn;
	res = f_opendir(&dir, path);
	if (res == FR_OK) 
	{
		for (;;) 
		{
			res = f_readdir(&dir, &fno);
			if (res != FR_OK || fno.fname[0] == 0) break;

			#if FF_USE_LFN
				fn = *fno.fname ? fno.fname : fno.altname;
			#else
				fn = fno.fname;
			#endif            
			//				
			if (fno.fattrib & AM_DIR) 
			{
				char dirname[50];
				if(fn[0]!='.')
				{
					sprintf(dirname,"%s/%s",path,fn);
					Print_Files(dirname);
				}
			} 
			else 
			{
				printf("%s/%s\t%dbyte\r\n", path, fn,(int)fno.fsize);
			}	 
		}
	}
	else
		printf("path(%s) not found\r\n",path);
}
void creat_files(void)
{
	FRESULT res;
	
	res = f_open(&fil, "0:/zc/myfile1.txt", FA_CREATE_NEW);
	if(res == FR_OK) {
		res = f_close(&fil);
	}
	res = f_open(&fil, "0:/zc/myfile2.txt", FA_CREATE_NEW);
	if(res == FR_OK) {
		res = f_close(&fil);
	}
	res = f_open(&fil, "0:/zc/myfile3.txt", FA_CREATE_NEW);
	if(res == FR_OK) {
		res = f_close(&fil);
	}
	res = f_open(&fil, "0:/zc/myfile4.txt", FA_CREATE_NEW);
	if(res == FR_OK) {
		res = f_close(&fil);
	}
	res = f_open(&fil, "0:/zc/myfile5.txt", FA_CREATE_NEW);
	if(res == FR_OK) {
		res = f_close(&fil);
	}
}
void write_files(void)
{
	FRESULT res;
	
	res = f_open(&fil, "0:/zc/myfile4.txt", FA_WRITE);
	if(res == FR_OK) {
		f_lseek(&fil, fil.obj.objsize);
		res = f_write(&fil, "i am boy\r\n", strlen("i am boy\r\n"), &bw);
		f_close(&fil);
	}
}

void read_files(void)
{
	FRESULT res;
	uint32_t filesize = 0;
	char buffer[200] = {0};
	
	res = f_open(&fil, "0:/zc/myfile4.txt", FA_READ);
	if(res == FR_OK) {
		filesize = f_size(&fil);
		res = f_read(&fil, buffer, filesize, &bw);
		printf("%s",buffer);
		f_close(&fil);
	}
}
DSTATUS disk_status(BYTE pdrv)
{
	DSTATUS status = STA_NOINIT;
	
	switch (pdrv) {
    case SPI_FLASH:      
			status = RES_OK;
			break;
		default:
			status = STA_NOINIT;
	}
	return status;
}

DSTATUS disk_initialize(BYTE pdrv)
{
	DSTATUS status = STA_NOINIT;	
	switch (pdrv) {			
		case SPI_FLASH:	  
			status = RES_OK;
		break;
			
		default:
			status = STA_NOINIT;
		break;
	}
	return status;
}

DRESULT disk_read(BYTE pdrv,BYTE *buff,DWORD sector,UINT count)
{
	DRESULT status = RES_PARERR;
	
	switch (pdrv) {
		case SPI_FLASH:
			spiflash_read(buff, sector <<12, count<<12);
			status = RES_OK;
		break;
				
		default:
			status = RES_PARERR;
	}
	return status;
}

DRESULT disk_write(BYTE pdrv,const BYTE *buff,DWORD sector,UINT count)
{
	DRESULT status = RES_PARERR;
	
	if (!count) {
		return RES_PARERR;		
	}

	switch (pdrv) {
		case SPI_FLASH:  
			spiflash_write((uint8_t *)buff,sector<<12,count<<12);
			status = RES_OK;
		break;
		
		default:
			status = RES_PARERR;
		break;
	}
	return status;
}

DRESULT disk_ioctl (BYTE pdrv,BYTE cmd,void *buff)
{
	DRESULT status = RES_PARERR;
	switch (pdrv) 
	{
		case SPI_FLASH:
			switch (cmd) 
			{
				case GET_SECTOR_COUNT:
					*(DWORD * )buff = FLASH_SECTOR_COUNT;	
				break;
				case GET_SECTOR_SIZE :
					*(WORD * )buff = FLASH_SECTOR_SIZE;
				break;
				case GET_BLOCK_SIZE :
					*(DWORD * )buff = 1;
				break;        
			}
			status = RES_OK;
		break;
			
		default:
			status = RES_PARERR;
		break;
	}
	return status;
}

